<?php
/**
 * Created by PhpStorm.
 * User: meng
 * Date: 2021/7/26
 * Time: 1:25 下午
 */

namespace app\utils;


use app\admin\model\FileModel;
use app\lib\exception\FileException;
use Exception;
use think\facade\Config;
use think\facade\Filesystem;
use think\File as tpFile;

class FileUtils
{
    // 允许文件类型列表
    protected $includes;
    // 不允许文件类型列表
    protected $excludes;
    // 单个文件最大限制
    protected $singleLimit;
    // 多文件上传最大限制
    protected $totalLimit;
    // 多文件上传最大数量
    protected $nums;
    // 文件存储目录
    protected $storeDir;
    // 文件对象
    protected $files;
    // 基础目录
    protected $local = '';

    public function __construct ($files, $config = []) {
        $this->files = is_array($files) ? $files : [$files];
        $this->includes = [];
        $this->excludes = [];
        $this->singleLimit = 0;
        $this->totalLimit = 0;
        $this->nums = 0;
        $this->storeDir = '';
        // 加载配置
        $this->loadConf($config);
        // 验证图片
        $this->verify();
    }

    /**
     * 文件上传
     * @param bool $single 是否单文件上传
     * @return array|mixed
     * @throws FileException
     */
    public function upload ($single = false): array {
        $ret = [];
        foreach ($this->files as $k => $file) {
            $md5 = $this->getMd5($file);
            try {
                $exists = FileModel::where('md5', $md5)->find();
            } catch (Exception $e) {
                throw new FileException('文件上传失败');
            }
            if (!empty($exists)) {
                array_push($ret, [
                    'id'   => $exists['id'],
                    'key'  => $k,
                    'path' => $exists['path'],
                    'url'  => $this->local . '/' . $exists['path']
                ]);
            } else {
                $savename = Filesystem::disk('file')->putFile($this->storeDir, $file);
                if (!$savename) {
                    throw new FileException('文件上传失败');
                }
                $size = $this->getSize($file);
                $ext = $this->getExt($file);
                $fileModel = FileModel::create([
                    'path'        => $savename,
                    'ext'         => $ext,
                    'size'        => $size,
                    'md5'         => $md5,
                    'create_time' => date('Y-m-d H:i:s')
                ]);
                array_push($ret, [
                    'id'   => $fileModel['id'],
                    'key'  => $k,
                    'path' => $savename,
                    'url'  => $this->local . '/' . $savename
                ]);
            }
        }
        return $single ? $ret[0] : $ret;
    }

    // 加载配置
    protected function loadConf ($config) {
        $default = Config::get('file');
        $this->includes = $config['include'] ?? $default['include'];
        $this->excludes = $config['exclude'] ?? $default['exclude'];
        $this->singleLimit = $config['single_limit'] ?? $default['single_limit'];
        $this->totalLimit = $config['total_limit'] ?? $default['total_limit'];
        $this->nums = $config['nums'] ?? $default['nums'];
        $this->storeDir = $config['store_dir'] ?? $default['store_dir'];
    }

    // 验证文件资源
    protected function verify () {
        if (empty($this->files)) {
            throw new FileException('未找到文件资源');
        }
        $this->allowFile();
        $this->allowFileSize();
    }

    // 验证文件类型
    protected function allowFile (): bool {
        if ((!empty($this->includes) && !empty($this->excludes)) || !empty($this->includes)) {
            foreach ($this->files as $v) {
                $ext = $this->getExt($v);
                if (!$ext || !in_array($ext, $this->includes)) {
                    throw new FileException('文件扩展名不合法');
                }
            }
        } else if (!empty($this->excludes) && empty($this->includes)) {
            foreach ($this->files as $v) {
                $ext = $this->getExt($v);
                if (!$ext || in_array($ext, $this->excludes)) {
                    throw new FileException('文件扩展名不合法');
                }
            }
        }
        return true;
    }

    // 验证文件大小
    protected function allowFileSize () {
        $fileCount = count($this->files);
        if ($fileCount > $this->nums) {
            throw new FileException('文件数量过多');
        }
        $totalSize = 0;
        foreach ($this->files as $v) {
            $fileSize = $this->getSize($v);
            if ($fileSize > $this->singleLimit) {
                throw new FileException('文件体积过大');
            }
            $totalSize += $fileSize;
        }
        if ($totalSize > $this->totalLimit) {
            throw new FileException('文件体积过大');
        }
    }

    // 获取文件大小
    protected function getSize (tpFile $file): int {
        return $file->getSize();
    }

    // 获取后缀名
    protected function getExt (tpFile $file): string {
        return $file->extension();
    }

    // 获取文件MD5
    protected function getMd5 (tpFile $file): string {
        return $file->md5();
    }

}
